package com.qsw.qswcommonlib.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 日期时间格式化
 */
public class CommonDateTimeUtil {

    private static final SimpleDateFormat FORMAT_DATE_TIME_12 = new SimpleDateFormat("yyyy-MM-dd, hh:mm:ss aa");
    private static final SimpleDateFormat FORMAT_DATE_TIME_24 = new SimpleDateFormat("yyyy-MM-dd, HH:mm:ss");
    private static final SimpleDateFormat FORMAT_DATE = new SimpleDateFormat("yyyy-MM-dd");
    private static final SimpleDateFormat FORMAT_TIME_12 = new SimpleDateFormat("hh:mm:ss aa");
    private static final SimpleDateFormat FORMAT_TIME_24 = new SimpleDateFormat("HH:mm:ss");

    private CommonDateTimeUtil() {
    }

    /**
     * 时间戳转换为日期及时间字符串，时间为12小时制，格式为：{@link #FORMAT_DATE_TIME_12}
     *
     * @param timestamp 时间戳
     * @return 转换字符串
     */
    public static String timestampToDateTime12Str(long timestamp) {
        return FORMAT_DATE_TIME_12.format(new Date(timestamp));
    }

    /**
     * 时间戳转换为日期及时间字符串，时间为24小时制，格式为：{@link #FORMAT_DATE_TIME_24}
     *
     * @param timestamp 时间戳
     * @return 转换字符串
     */
    public static String timestampToDateTime24Str(long timestamp) {
        return FORMAT_DATE_TIME_24.format(new Date(timestamp));
    }

    /**
     * 时间戳转换为时间字符串，时间为12小时制，格式为：{@link #FORMAT_TIME_12}
     *
     * @param timestamp 时间戳
     * @return 转换字符串
     */
    public static String timestampToTime12Str(long timestamp) {
        return FORMAT_TIME_12.format(new Date(timestamp));
    }

    /**
     * 时间戳转换为时间字符串，时间为12小时制
     *
     * @param timestamp 时间戳
     * @param separator 时分秒之间的分隔符
     * @return 转换字符串
     */
    public static String timestampToTime12Str(long timestamp, String separator) {
        return timestampToTime12Str(timestamp, separator, true);
    }

    /**
     * 时间戳转换为时间字符串，时间为12小时制
     *
     * @param timestamp 时间戳
     * @param separator 时分秒之间的分隔符
     * @param showAMPM  是否显示AMPM标记
     * @return 转换字符串
     */
    public static String timestampToTime12Str(long timestamp, String separator, boolean showAMPM) {
        return new SimpleDateFormat("hh" + separator + "mm" + separator + "ss" + (showAMPM ? " aa" : "")).format(new Date(timestamp));
    }

    /**
     * 时间戳转换为时间字符串，时间为24小时制，格式为：{@link #FORMAT_TIME_24}
     *
     * @param timestamp 时间戳
     * @return 转换字符串
     */
    public static String timestampToTime24Str(long timestamp) {
        return FORMAT_TIME_24.format(new Date(timestamp));
    }

    /**
     * 时间戳转换为时间字符串，时间为24小时制
     *
     * @param timestamp 时间戳
     * @param separator 时分秒之间的分隔符
     * @return 转换字符串
     */
    public static String timestampToTime24Str(long timestamp, String separator) {
        return new SimpleDateFormat("HH" + separator + "mm" + separator + "ss").format(new Date(timestamp));
    }

    /**
     * 时间戳转换为日期字符串，格式为：{@link #FORMAT_DATE}
     *
     * @param timestamp 时间戳
     * @return 转换字符串
     */
    public static String timestampToDateStr(long timestamp) {
        return FORMAT_DATE.format(new Date(timestamp));
    }

    /**
     * 时间戳转换为日期字符串
     *
     * @param timestamp 时间戳
     * @param separator 年月日之间的分隔符
     * @return 转换字符串
     */
    public static String timestampToDateStr(long timestamp, String separator) {
        return new SimpleDateFormat("yyyy" + separator + "MM" + separator + "dd").format(new Date(timestamp));
    }

    /**
     * 时间戳转换为年月日时分秒，月份已转换为正常数字，时间为12小时制
     *
     * @param timestamp 时间戳
     * @return 共7个值，年、月、日、时、分、秒索引分别为0 - 5，索引6对应0为上午，1为下午
     */
    public static int[] timestampToDateTime12(long timestamp) {
        int[] dateTime12 = timestampToOriginalDateTime12(timestamp);
        dateTime12[1] += 1;
        return dateTime12;
    }

    /**
     * 时间戳转换为年月日时分秒，时间为12小时制
     *
     * @param timestamp 时间戳
     * @return 共7个值，年、月、日、时、分、秒索引分别为0 - 5，索引6对应0为上午，1为下午
     */
    public static int[] timestampToOriginalDateTime12(long timestamp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp);
        return new int[]{calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH),
                calendar.get(Calendar.HOUR),
                calendar.get(Calendar.MINUTE),
                calendar.get(Calendar.SECOND),
                calendar.get(Calendar.AM_PM)};
    }

    /**
     * 时间戳转换为年月日时分秒，月份已转换为正常数字，时间为24小时制
     *
     * @param timestamp 时间戳
     * @return 共6个值，年、月、日、时、分、秒索引分别为0 - 5
     */
    public static int[] timestampToDateTime24(long timestamp) {
        int[] dateTime24 = timestampToOriginalDateTime24(timestamp);
        dateTime24[1] += 1;
        return dateTime24;
    }

    /**
     * 时间戳转换为年月日时分秒，时间为24小时制
     *
     * @param timestamp 时间戳
     * @return 共6个值，年、月、日、时、分、秒索引分别为0 - 5
     */
    public static int[] timestampToOriginalDateTime24(long timestamp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp);
        return new int[]{calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH),
                calendar.get(Calendar.HOUR_OF_DAY),
                calendar.get(Calendar.MINUTE),
                calendar.get(Calendar.SECOND)};
    }

    /**
     * 计算两个时间戳之间的时间差
     *
     * @param timestampBegin 开始的时间戳
     * @param timestampEnd   结束的时间戳
     * @return 共5个值，从0 - 4分别为相差的日、时、分、秒、毫秒
     */
    public static int[] timestampInterval(long timestampBegin, long timestampEnd) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        long ns = 1000;
        long diff = timestampEnd - timestampBegin;
        // 计算差多少天
        int day = (int) (diff / nd);
        // 计算差多少小时
        int hour = (int) (diff % nd / nh);
        // 计算差多少分钟
        int min = (int) (diff % nd % nh / nm);
        // 计算差多少秒
        int sec = (int) (diff % nd % nh % nm / ns);
        // 计算差多少毫秒
        int mil = (int) (diff % nd % nh % nm % ns);
        return new int[]{day, hour, min, sec, mil};
    }

    /**
     * 根据年和月获取该月有几天
     *
     * @param year  年
     * @param month 月
     * @return 该月一共有几天
     */
    public static int getDayNumOfMonth(int year, int month) {
        int day = 0;
        if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
            day = 29;
        } else {
            day = 28;
        }
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                return 31;
            case 4:
            case 6:
            case 9:
            case 11:
                return 30;
            case 2:
                return day;
        }
        return 0;
    }

    /**
     * 获取指定时间戳往后增加指定天数后的具体日期
     *
     * @param ms  起始时间戳
     * @param day 增加的天数
     * @return 数组长度为3，索引从0-2分别为：年、月、日，其中“月”已转换为正常逻辑
     */
    public static int[] getDateFromMs(long ms, int day) {
        int[] originalDateFromMs = getOriginalDateFromMs(ms, day);
        originalDateFromMs[1] += 1;
        return originalDateFromMs;
    }

    /**
     * 获取指定时间戳往后增加指定天数后的具体日期
     *
     * @param ms  起始时间戳
     * @param day 增加的天数
     * @return 数组长度为3，索引从0-2分别为：年、月、日
     */
    public static int[] getOriginalDateFromMs(long ms, int day) {
        ms += day * 24L * 60 * 60 * 1000;
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(ms);
        int[] result = new int[]{
                calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH)
        };
        return result;
    }

    /**
     * 计算自起始日开始经历了几年
     *
     * @param timestampBegin 开始的时间戳
     * @param timestampEnd   结束的时间戳
     * @param add            true：不足1年则按1年计算；false：不足1年则舍去
     * @return 相差的
     */
    public static int intervalYear(long timestampBegin, long timestampEnd, boolean add) {
        if (timestampBegin > timestampEnd) {
            return Integer.MIN_VALUE;
        }
        Calendar calendar = Calendar.getInstance();

        calendar.setTimeInMillis(timestampBegin);
        int startYear = calendar.get(Calendar.YEAR);
        int startMonth = calendar.get(Calendar.MONTH);
        int startDay = calendar.get(Calendar.DAY_OF_MONTH);

        calendar.setTimeInMillis(timestampEnd);
        int endYear = calendar.get(Calendar.YEAR);
        int endMonth = calendar.get(Calendar.MONTH);
        int endDay = calendar.get(Calendar.DAY_OF_MONTH);

        int intervalYear = endYear - startYear;
        if (intervalYear == 0) {
            intervalYear = add ? 1 : 0;
        } else {
            if (endMonth < startMonth) {
                if (!add) {
                    intervalYear--;
                }
            } else if (endMonth > startMonth) {
                if (add) {
                    intervalYear++;
                }
            } else {
                if (endDay < startDay) {
                    if (!add) {
                        intervalYear--;
                    }
                } else if (endDay > startDay) {
                    if (add) {
                        intervalYear++;
                    }
                }
            }
        }
        return intervalYear;
    }

    /**
     * 计算自起始日开始经历了几个月
     *
     * @param timestampBegin 开始的时间戳
     * @param timestampEnd   结束的时间戳
     * @param add            true：不足1月则按1月计算；false：不足1月则舍去
     * @return 相差的
     */
    public static int intervalMonth(long timestampBegin, long timestampEnd, boolean add) {
        if (timestampBegin > timestampEnd) {
            return Integer.MIN_VALUE;
        }
        Calendar calendar = Calendar.getInstance();

        calendar.setTimeInMillis(timestampBegin);
        int startMonth = calendar.get(Calendar.MONTH);
        int startDay = calendar.get(Calendar.DAY_OF_MONTH);

        calendar.setTimeInMillis(timestampEnd);
        int endMonth = calendar.get(Calendar.MONTH);
        int endDay = calendar.get(Calendar.DAY_OF_MONTH);

        int intervalYear = intervalYear(timestampBegin, timestampEnd, false);

        int intervalMonth = add ? 1 : 0;
        if (endMonth < startMonth) {
            if (endDay < startDay) {
                intervalMonth = 12 - startMonth + endMonth + (add ? 0 : -1);
            } else if (endDay > startDay) {
                intervalMonth = 12 - startMonth + endMonth + (add ? 1 : 0);
            } else {
                intervalMonth = 12 - startMonth + endMonth;
            }
        } else if (endMonth > startMonth) {
            if (endDay < startDay) {
                intervalMonth = -startMonth + endMonth + (add ? 0 : -1);
            } else if (endDay > startDay) {
                intervalMonth = -startMonth + endMonth + (add ? 1 : 0);
            } else {
                intervalMonth = -startMonth + endMonth;
            }
        } else {
            if (endDay < startDay) {
                intervalMonth = 12 + (add ? 0 : -1);
            } else if (endDay > startDay) {
                intervalMonth = add ? 1 : 0;
            }
        }

        return intervalYear * 12 + intervalMonth;
    }

    /**
     * 计算自起始日开始经历了几天
     *
     * @param timestampBegin 开始的时间戳
     * @param timestampEnd   结束的时间戳
     * @return 相差的
     */
    public static int intervalDay(long timestampBegin, long timestampEnd) {
        if (timestampBegin > timestampEnd) {
            return Integer.MIN_VALUE;
        }
        Calendar calendar = Calendar.getInstance();

        calendar.setTimeInMillis(timestampBegin);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long start = calendar.getTimeInMillis();

        calendar.setTimeInMillis(timestampEnd);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long end = calendar.getTimeInMillis();

        long nd = 1000 * 24 * 60 * 60;
        long diff = end - start;

        return (int) (diff / nd);
    }

}
